#include <string.h>

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>

#include "esp_console.h"
#include "argtable3/argtable3.h"
#include "cmd_decl.h"


#include "ping/ping.h"
#include "esp_ping.h"

#include "console_ping.h"


/** 'ping' command ping dest domain name or ip */

static struct 
{
    struct arg_int *count;
    struct arg_str *domain;
    struct arg_end *end;
}ping_args;


ip4_addr_t ip_hex;
char ip_str[16] = {0};

bool ping_running = false;


esp_err_t pingResults(ping_target_id_t msgType, esp_ping_found * pf){
	// printf("AvgTime:%.1fmS Sent:%d Rec:%d Err:%d min(mS):%d max(mS):%d ", 
    //         (float)pf->total_time/pf->recv_count,
    //         pf->send_count, pf->recv_count,
    //         pf->err_count, pf->min_time, pf->max_time );
	// printf("Resp(mS):%d Timeouts:%d Total Time:%d\n",pf->resp_time, pf->timeout_count, pf->total_time);

    if(pf->ping_err ==  PING_RES_TIMEOUT)
    {
        printf("%s respone timout\n",ip_str);
    }
    else if(pf->ping_err == PING_RES_OK)
    {
        printf("bytes %d from %s: seqno:%d time:%d ms\n",pf->bytes,ip_str,pf->send_count,pf->resp_time);
    }
    else if(pf->ping_err == PING_RES_FINISH)
    {
        printf("\n--- %s(%s) ping statistics ---\n",ping_args.domain->sval[0],ip_str);

        printf("%d packets transmitted, %d received, %.3f%% packet loss, total time %d ms\n",
                pf->send_count,pf->recv_count,(float)(pf->send_count-pf->recv_count)/pf->send_count*100,pf->total_time);

        printf("result min/avg/max=%d/%.3f/%d ms\na",pf->min_time,(float)pf->total_time/pf->recv_count,pf->max_time);

        // ping_running = false;
    }



	return ESP_OK;
}

// 根据域名获取ip  
int get_ip_by_domain(const char *domain, char *ip)  
{  
    char **pptr;  
    struct hostent *hptr;  
  
    hptr = gethostbyname(domain);  
    if(NULL == hptr)  
    {  
        printf("gethostbyname error for host:%s/n", domain);  
        return -1;  
    }  

    for(pptr = hptr->h_addr_list ; *pptr != NULL; pptr++)  
    {  
        if (NULL != inet_ntop(hptr->h_addrtype, *pptr, ip, 14) )  
        {  
            return 0; // 只获取第一个 ip  
        }  
    }  
  
    return -1;  
}  

void start_ping(const char* domain,int count)
{
    memset(ip_str,0,sizeof(ip_str));
    get_ip_by_domain(domain,ip_str);

    ip4addr_aton(ip_str,(ip4_addr_t*)&ip_hex.addr);

    uint32_t ping_count = 4;  //how many pings per report
    uint32_t ping_timeout = 2000; //mS till we consider it timed out
    uint32_t ping_delay = 500; //mS between pings

    if(count > 0)
         ping_count = count;

    
    esp_ping_set_target(PING_TARGET_IP_ADDRESS_COUNT, &ping_count, sizeof(uint32_t));
    esp_ping_set_target(PING_TARGET_RCV_TIMEO, &ping_timeout, sizeof(uint32_t));
    esp_ping_set_target(PING_TARGET_DELAY_TIME, &ping_delay, sizeof(uint32_t));
    esp_ping_set_target(PING_TARGET_IP_ADDRESS, &ip_hex.addr, sizeof(uint32_t));
    esp_ping_set_target(PING_TARGET_RES_FN, &pingResults, sizeof(pingResults));

    ping_init();

    printf("PING %s(%s)\n",domain,ip_str);

    // ping_running = true;
    
       
}


static int ping(int argc, char** argv)
{
    int nerrors = arg_parse(argc, argv, (void**) &ping_args);
    if (nerrors != 0) {
        arg_print_errors(stderr, ping_args.end, argv[0]);
        return 1;
    }

    int count = 0;

    if(ping_args.count->count >0 )
    {
        // if(ping_args.count->ival[0] >0 && ping_args.count->ival[0]<MAX_PING_TIME)
        if(ping_args.count->ival[0]<=MAX_PING_TIMES)
            count = ping_args.count->ival[0];
        else
        {
            printf("count mast < %d\n",MAX_PING_TIMES);
            return 1;
        }
         
    }

    if(ping_args.domain->count > 0)
    { 
        if(ping_args.domain->count > 1)
        {
            printf("Domain name or IP must be only one\n");            
            return 1;
        }

        start_ping(ping_args.domain->sval[0],count);

        // while(ping_running)
        // {
        //     char c = getchar();
        //     if(c == 'q' || c=='Q')
        //     {
        //         ping_deinit();
        //         printf("stop ping\n");
        //     }
        //     else
        //     {
        //         printf("invalid char\n");
        //     }
            
        // }

    }
    else
    {
        printf("Domain name or IP must be entered\n");
    
        return 1;
    }
    


    return 0;
}

void register_ping()
{
    ping_args.count = arg_int0("c","count","<n>","ping count<1-30>");
    ping_args.domain = arg_str1(NULL,NULL,"<dest>","domain or ip");
    ping_args.end = arg_end(3);

    const esp_console_cmd_t cmd = {
        .command = "ping",
        .help = "ping dest domain or ip",
        .hint = NULL,
        .func = &ping,
        .argtable = &ping_args
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
 